package com.starblink.imgsearch.findsimilar.ui

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.graphics.Bitmap
import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.media.MediaPlayer
import android.util.Log
import android.util.Size
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager.widget.ViewPager
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.bumptech.glide.Glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomViewTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
import com.starblink.android.basic.adapter.MutableAdapter
import com.starblink.android.basic.base.activity.BaseTVMActivity
import com.starblink.android.basic.data.model.product.ProductFWrap
import com.starblink.android.basic.ext.bindFragment
import com.starblink.android.basic.ext.enableCorner
import com.starblink.android.basic.ext.gone
import com.starblink.android.basic.ext.visible
import com.starblink.android.basic.extension.apollo.toWrap
import com.starblink.android.basic.extension.dp2px
import com.starblink.android.basic.extension.lazyOnNone
import com.starblink.android.basic.extension.navigationTo
import com.starblink.android.basic.sensorsdata.extension.trackData
import com.starblink.android.basic.sensorsdata.room.entity.SkAntEntity
import com.starblink.android.basic.sensorsdata.spm.GTrackerAssistUtils
import com.starblink.android.basic.sensorsdata.spm.cfg.SpmElementDef
import com.starblink.android.basic.sensorsdata.spm.cfg.SpmPageDef
import com.starblink.android.basic.sensorsdata.spm.event.TrackEvent
import com.starblink.android.basic.sensorsdata.spm.impl.SpmTrackHandler
import com.starblink.imgsearch.databinding.ActivityFindsimilarResultBinding
import com.starblink.imgsearch.result.ext.box2RectF

import com.starblink.basic.ext.appScreenHeight
import com.starblink.basic.ext.createBitmap
import com.starblink.basic.ext.nowTime
import com.starblink.basic.ext.scale
import com.starblink.basic.route.RoutePage
import com.starblink.basic.style.bottomsheet.PagerBottomSheetBehavior
import com.starblink.basic.style.view.recyclerview.SimpleGapItemDecor
import com.starblink.imgsearch.ext.defaultBoxRect
import com.starblink.imgsearch.findsimilar.ui.cell.SimilarImgClipTabCell
import com.starblink.imgsearch.findsimilar.ui.fragment.SimilarTabFragment
import com.starblink.imgsearch.result.data.ImgClipModel
import com.starblink.imgsearch.result.ext.rect2BoxStr
import com.starblink.imgsearch.result.ui.widget.ThingsPagerAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import razerdp.blur.BlurHelper

/**
 * 找相似结果页
 */
@Route(path = RoutePage.ImageSearch.PAGE_FIND_SIMILAR)
class ImgFindSimilarActivity :
    BaseTVMActivity<ActivityFindsimilarResultBinding, FindSimilarVM>(), ViewPager.OnPageChangeListener {

    override fun isStatusBarLightMode(): Boolean = false

    override fun initViewBinding(): ActivityFindsimilarResultBinding =
        ActivityFindsimilarResultBinding.inflate(layoutInflater)

    @Autowired(name = RoutePage.ARG.TYPE)
    @JvmField
    var type: Int = 1

    @Autowired(name = RoutePage.ImageSearch.ARGS_IMG_URL)
    @JvmField
    var imgUrl: String = ""

    @Autowired(name = RoutePage.ARG.ID)
    @JvmField
    var productId: String = ""

    private val btSheetCallback by lazyOnNone<PagerBottomSheetBehavior.BottomSheetCallback> {
        object : PagerBottomSheetBehavior.BottomSheetCallback() {
            override fun onStateChanged(bottomSheet: View, newState: Int) {
                //Log.d(TAG, "onStateChanged : $newState")
                fragments.forEachIndexed { _, similarTabFragment ->
                    similarTabFragment.bottomSheetExpand = newState == PagerBottomSheetBehavior.STATE_EXPANDED
                }
            }

            override fun onSlide(bottomSheet: View, slideOffset: Float) {
//                Log.d(TAG, "onSlide : $slideOffset")
                viewBinding.vBgMask.alpha = slideOffset * 0.8f
                viewBinding.imgDim.alpha = slideOffset * 0.8f
            }

        }
    }

    private var bottomSheetBehavior: PagerBottomSheetBehavior<View>? = null

    private var scanAnimator: ObjectAnimator? = null

    private var imgSize: Size? = null

    private var imgBmp: Bitmap? = null

    private val clipImgAdapter by lazyOnNone {
        MutableAdapter(viewModel.imgClipData).apply {
            addVhDelegate {
                SimilarImgClipTabCell(it) { position ->
                    viewBinding.viewPager.setCurrentItem(position, true)
                }
            }
        }
    }

    private var mp: MediaPlayer? = null

    private var pagerAdapter: ThingsPagerAdapter? = null

    private var fragments = arrayListOf<SimilarTabFragment>()


    override fun onDestroy() {
        mp?.release()
        scanAnimator?.cancel()
        super.onDestroy()
    }

    override fun initData() {
        super.initData()
        viewModel.type = type
        viewModel.productId = productId
        viewModel.imgUrl = imgUrl
        viewModel.loadData()
    }

    override fun initView() {
        super.initView()
        loadImg()
        viewBinding.btnBack.setOnClickListener {
            finish()
        }
        viewBinding.btnCancel.setOnClickListener {
            finish()
        }
        viewBinding.loadingLayout.visible()
        viewBinding.imgAnim.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            topMargin = appScreenHeight / 8
        }
        scanAnimator = ObjectAnimator.ofFloat(
            viewBinding.imgAnim,
            "translationY",
            0f,
            appScreenHeight.shr(1).toFloat() + 100.dp2px(),
        ).apply {
            repeatMode = ValueAnimator.RESTART
            repeatCount = ValueAnimator.INFINITE
            duration = 2500L
            interpolator = AccelerateDecelerateInterpolator()
            start()
        }

        viewModel.dataLD.observe(this) {
            onViewSuccess()
        }
        viewBinding.btnSearch.enableCorner(1000)
        viewBinding.btnSearch.trackData(
            element = SpmElementDef.DiscoverSearch,
            page = SpmPageDef.FIND_SIMILAR_PAGE,
            onlyHit=true
        )
        viewBinding.btnSearch.setOnClickListener {
            navigationTo(RoutePage.Search.PAGE_SEARCH)
        }
        pageExposure(SpmPageDef.IMG_SEARCHING)
        viewBinding.btnCancel.trackData(
            element = SpmElementDef.ScanCameraCancel,
            page = SpmPageDef.IMG_SEARCHING,
            onlyHit=true
        )
    }

    private fun loadImg() {
        viewBinding.img.adjustViewBounds = true
        viewBinding.imgDim.adjustViewBounds = true
        Glide.with(this).asBitmap().apply(RequestOptions().apply {
            format(DecodeFormat.PREFER_ARGB_8888)
        }).override(Target.SIZE_ORIGINAL).load(imgUrl)
            .skipMemoryCache(false)
            .priority(Priority.IMMEDIATE)
            .into(object : CustomViewTarget<ImageView, Bitmap>(viewBinding.img) {
                override fun onLoadFailed(errorDrawable: Drawable?) {

                }

                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    imgBmp = resource //Bitmap.createBitmap(resource)
                    viewBinding.img.setImageBitmap(imgBmp)
                    viewBinding.img.viewTreeObserver.addOnPreDrawListener(object :
                        ViewTreeObserver.OnPreDrawListener {
                        override fun onPreDraw(): Boolean {
                            viewBinding.img.updateLayoutParams {
                                val cRadio =
                                    viewBinding.vMeasure.width.toFloat() / viewBinding.vMeasure.measuredHeight
                                imgSize = Size(resource.width, resource.height)
                                if (imgSize!!.width.toFloat() / imgSize!!.height >= cRadio) {
                                    width = viewBinding.vMeasure.width
                                    height = ViewGroup.LayoutParams.WRAP_CONTENT

                                } else {
                                    height = viewBinding.vMeasure.height
                                    width = ViewGroup.LayoutParams.WRAP_CONTENT
                                }

                                viewBinding.imgDim.layoutParams?.width = width
                                viewBinding.imgDim.layoutParams?.height = height
                            }
                            lifecycleScope.launch(Dispatchers.IO) {
                                try {
                                    val blurBmp = BlurHelper.blur(
                                        this@ImgFindSimilarActivity,
                                        Bitmap.createBitmap(imgBmp!!), // 创建新对象，内部调用会recycle
                                        viewBinding.img.width,
                                        viewBinding.img.height,
                                        10f,
                                    )
                                    lifecycleScope.launch {
                                        viewBinding.imgDim.setImageBitmap(blurBmp)
                                    }
                                } catch (ex: Exception) {
                                    ex.printStackTrace()
                                }
                            }
                            viewBinding.img.viewTreeObserver.removeOnPreDrawListener(this)
                            initThingsAndView()
                            return true
                        }

                    })
                }

                override fun onResourceCleared(placeholder: Drawable?) {
                    Log.d(TAG, "onResourceCleared: ${placeholder?.intrinsicWidth}")
                }

            })
    }

    private fun onViewSuccess() {
        val tag = nowTime()
        viewBinding.imgContainer.updateLayoutParams<FrameLayout.LayoutParams> {
            gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
        }
        viewBinding.resultLayout.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            topMargin = 0
        }
        viewBinding.resContentLayout.updateLayoutParams<CoordinatorLayout.LayoutParams> {
            bottomSheetBehavior = (this.behavior as? PagerBottomSheetBehavior<View>)?.also {
                it.addBottomSheetCallback(btSheetCallback)
            }
        }
        viewBinding.imgContainer.radius = 0f
        //viewBinding.viewPager.enableCorner(32.dp2px(), "top")
        viewBinding.vBgMask.visible()
        viewBinding.imgDim.visible()
        anim2Top(1000L)

        val data = viewModel.dataLD.value
        pagerAdapter = ThingsPagerAdapter(supportFragmentManager, fragments)
        if (viewModel.boxesList.isEmpty()) {
            fragments.add(
                createFragment(
                    0,
                    "",
                    data?.productList?.mapIndexed { i, p -> p.productF.toWrap(i) })
            )
        } else {
            viewModel.boxesList.let {
                it.forEachIndexed { index, s ->
                    fragments.add(
                        createFragment(
                            index,
                            s ?: "",
                            if (s == viewModel.curBox) data?.productList?.mapIndexed { i, p ->
                                p.productF.toWrap(
                                    i
                                )
                            } else null))
                }
            }
        }
        viewBinding.viewPager.bindFragment(
            pagerAdapter = pagerAdapter!!,
            pageChangeListener = this
        )
        //viewBinding.layMainGoods.setData(product = data?.currentProduct?.productF)


        bottomSheetBehavior?.also {
            it.peekHeight =
                if (viewBinding.img.measuredHeight > 0) {
                    val result = if (viewBinding.img.measuredHeight > appScreenHeight * 0.8) {
                        (appScreenHeight * 0.2).toInt()
                    } else {
                        (appScreenHeight  - viewBinding.root.paddingTop - viewBinding.img.measuredHeight - 10.dp2px())
                    }
                    result
                } else (appScreenHeight * 0.2).toInt()
            it.halfExpandedRatio = 0.6F
            it.expandedOffset
        }

        initThingsAndView()

        viewBinding.resultLayout.visible()
        viewBinding.loadingLayout.postDelayed({
            viewBinding.loadingLayout.gone()
            scanAnimator?.pause()
            scanAnimator?.cancel()
        }, 200L)
        Log.d(TAG, "layout main, spent time : ${nowTime() - tag} ms")
    }

    private fun anim2Top(delay: Long) {
        viewBinding.root.postDelayed({
            bottomSheetBehavior?.state = PagerBottomSheetBehavior.STATE_EXPANDED
        }, delay)
    }

    private fun initThingsAndView() {
        imgBmp ?: return
        imgSize ?: return
        if (!viewModel.dataLoaded) {
            return
        }

        // 为空时，本地补充一个空的
        val curRect = viewModel.curBox?.box2RectF() ?: imgSize!!.defaultBoxRect()
        viewModel.boxesList.map { it.box2RectF() }.let {
            viewModel.rectBoxes.addAll(it)
        }
        viewModel.rectBoxes.takeIf { it.isEmpty() }?.add(curRect)

        viewBinding.imgThings.trackPage = SpmPageDef.FIND_SIMILAR_PAGE
        viewBinding.imgThings.apply {
            updateLayoutParams<FrameLayout.LayoutParams> {
                this.width = viewBinding.img.measuredWidth
                this.height = viewBinding.img.measuredHeight
            }
            imgSize = this@ImgFindSimilarActivity.imgSize
            curRectF = curRect
            tingsRectF = viewModel.rectBoxes
            onDraggedPosition = {
                onDragged(it)
            }
            onHotPotClick = { position, rect ->
                viewBinding.viewPager.setCurrentItem(position, true)
            }
        }

        val curPosition = viewModel.rectBoxes.indexOfFirst { curRect == it }
        viewBinding.imgClips.layoutManager =
            LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        viewBinding.imgClips.addItemDecoration(SimpleGapItemDecor(8.dp2px(), withEdge = true))
        viewModel.imgClipData.clear()
        viewModel.rectBoxes.forEachIndexed { index, it ->
            viewModel.imgClipData.add(
                ImgClipModel(
                    imgBmp = imgBmp!!.createBitmap(it.left.toInt(),
                        it.top.toInt(),
                        it.width().toInt(),
                        it.height().toInt()),
                    selected = curPosition == index,
                ),
            )
        }
        viewBinding.imgClips.adapter = clipImgAdapter
        clipImgAdapter.refreshAll()
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {

    }

    override fun onPageSelected(position: Int) {
        viewModel.dataLD.value ?: return
        viewModel.rectBoxes.takeIf { it.isNotEmpty() && position < it.size }?.run {
            viewBinding.imgThings.curRectF = get(position)
        }
        viewModel.imgClipData.forEachIndexed { index, imgClipModel ->
            imgClipModel.selected = index == position
        }
        clipImgAdapter.refreshAll()

    }

    override fun onPageScrollStateChanged(state: Int) {

    }

    private fun onDragged(rect: RectF) {
        pagerAdapter ?: return

        SpmTrackHandler.addSingleTrackData(
            SkAntEntity(
                event = TrackEvent.elementClick.value,
                spmCnt = GTrackerAssistUtils.fetchElementValue(
                    SpmPageDef.FIND_SIMILAR_PAGE,
                    SpmElementDef.GuideScanImgResultDragAndAdjust
                ),
                params = mapOf()
            )
        )

        rect.scale(imgSize!!.width / viewBinding.imgThings.measuredWidth.toFloat())

        if (viewModel.rectBoxes.size >= MAX_TAB_SIZE || viewModel.isLastBoxFromDrag) {
            fragments.last().apply {
                picUrl = viewModel.imgUrl
                region = rect.rect2BoxStr()
                reload()
            }
            viewModel.rectBoxes.last().set(rect)
            viewModel.imgClipData.last().apply {
                imgBmp = this@ImgFindSimilarActivity.imgBmp!!.createBitmap(rect.left.toInt(),
                    rect.top.toInt(),
                    rect.width().toInt(),
                    rect.height().toInt())
                selected = true
            }
            clipImgAdapter.notifyItemChanged(viewModel.imgClipData.lastIndex)
        } else {
            fragments.add(
                createFragment(fragments.size, rect.rect2BoxStr(), null)
            )
            viewModel.imgClipData.add(
                ImgClipModel(
                    imgBmp = Bitmap.createBitmap(
                        imgBmp!!,
                        rect.left.toInt(),
                        rect.top.toInt(),
                        rect.width().toInt(),
                        rect.height().toInt()
                    ),
                    selected = true,
                ),
            )
            viewModel.rectBoxes.add(rect)
            //setThingsTabLayout()
            pagerAdapter?.notifyDataSetChanged()
            viewModel.isLastBoxFromDrag = true
        }
        viewBinding.viewPager.offscreenPageLimit = pagerAdapter!!.count - 1
        viewBinding.viewPager.setCurrentItem(pagerAdapter!!.count - 1, true)
        viewBinding.imgClips.scrollToPosition(viewModel.imgClipData.size - 1)

        anim2Top(200L)

        //viewModel.mainPrdMap[pagerAdapter!!.count - 1] = null
        //viewBinding.layMainGoods.setData(product = null)
    }

    private fun createFragment(position: Int, region: String, list : List<ProductFWrap?>?) = SimilarTabFragment.newInstance(
        position = position,
        picUrl = viewModel.imgUrl,
        region = region,
        productId = viewModel.productId,
        type = viewModel.type,
        list = list,
        mainProduct = viewModel.mainPrdMap[position],
    )



    companion object {
        const val MAX_TAB_SIZE = 6
        const val TAG = "FindSimilarActivity"
    }


}